/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/** *****************************************************************************************************
 * \file     fee_ops.c                                                                            *
 * \brief    AUTOSAR 4.3.1 MCAL Fee Driver                                                             *
 *                                                                                                      *
 * <table>                                                                                              *
 * <tr><th>Date           <th>Version                                                                   *
 * <tr><td>2024/07/02     <td>1.0.0                               *
 * </table>                                                                                             *
 *******************************************************************************************************/

/********************************************************************************************************
 *                                      Include header files                                            *
 *******************************************************************************************************/
#include "cdefs.h"
#include "cdefs.h"
#include "Fls.h"
#include "Fee.h"
#include "fee_ops.h"
#include "Fee_Cfg.h"
#include "debug.h"
#include "Mcal_MemLibc.h"
#if (FEE_CHECKSUM_SUPPORTED == STD_ON)
#include "Fee_Crc16.h"
#endif
#include "Fee_Fault.h"

// PRQA S 2755 EOF

/********************************************************************************************************
 *                                  Private Variable Definitions                                        *
 *******************************************************************************************************/
#define FEE_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Fee_MemMap.h"

/* record info buff */
static uint8 record_info_buff[FEE_INFO_CACHE_SIZE + CONFIG_ARCH_CACHE_LINE];
static uint8 record_data_buff[FEE_DATA_CACHE_SIZE + CONFIG_ARCH_CACHE_LINE];
#if (FEE_CHECKSUM_SUPPORTED == STD_ON)
uint8 block_buff[FEE_DATA_CACHE_SIZE + CONFIG_ARCH_CACHE_LINE];
#endif
static uint8 page0_sector_buf[FEE_SECTOR_BUFF_SIZE + CONFIG_ARCH_CACHE_LINE];
static uint8 page1_sector_buf[FEE_SECTOR_BUFF_SIZE + CONFIG_ARCH_CACHE_LINE];

/* page_status */
static uint8 page0_info_buf[sizeof(struct fee_page_info) +
                                         CONFIG_ARCH_CACHE_LINE];
static uint8 page1_info_buf[sizeof(struct fee_page_info) +
                                         CONFIG_ARCH_CACHE_LINE];
static uint8 block_info_buff[sizeof(struct fee_record_info) +
                                          CONFIG_ARCH_CACHE_LINE];

/*fee block info*/
struct fee_block_status block_status[FEE_BLOCKS_CFG_NUMBER];
struct fee_block_status block_status_backup[FEE_BLOCKS_CFG_NUMBER];

/* page index */
static uint32 g_sector_index;
static uint32 g_record_index;

static uint16 g_active_page;
static uint16 g_erase_page;

#define FEE_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Fee_MemMap.h"

#define FEE_START_SEC_VAR_INIT_UNSPECIFIED
#include "Fee_MemMap.h"

#define FEE_STOP_SEC_VAR_INIT_UNSPECIFIED
#include "Fee_MemMap.h"

//#define FEE_INFO_DUMP 1

#define FEE_START_SEC_CODE
#include "Fee_MemMap.h"

#if defined(FEE_INFO_DUMP)
/** *****************************************************************************************************
 * \brief This function dump data in hex.
 *
 * \verbatim
 * Syntax             : void hexdump8_fee_ex(const void *ptr, uint32 len,
                                   uint64 disp_addr)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : ptr - Pointer to data
 *                      len - data len
 *                      disp_addr - data address
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : None
 *
 * Description        : dump data in hex.
 * \endverbatim
 *******************************************************************************************************/
inline static void hexdump8_fee_ex(const void *ptr, uint32 len,
                                   uint64 disp_addr)
{
    uint32 address = (uint32)(const uint32 *)ptr;
    uint32 count;
    uint32 i;

    for (count = 0 ; count < len; count += 16) {
        FEE_ERROR("0x%08llx: ", count);

        for (i = 0; i < _MIN(len - count, 16); i++) {
            FEE_ERROR("%02x ", *(const uint8 *)(address + i));
        }

        for (; i < 16; i++) {
            FEE_ERROR("   ");
        }

        FEE_ERROR("|");

        for (i = 0; i < _MIN(len - count, 16); i++) {
            char c = ((const char *)address)[i];
            /*PRQA S 1880 2*/
            FEE_ERROR("%c", ((c >= 0x20) && (c < 0x7f)) ? c : '.');
            (void)c;
        }

        FEE_ERROR("\n");
        address += 16;
    }
}
#endif

#define FEE_STOP_SEC_CODE
#include "Fee_MemMap.h"

/** *****************************************************************************************************
 * \brief This function get block index based on block number.
 *
 * \verbatim
 * Syntax             : uint16 fee_number_to_index(uint16 block_number)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : block_number - block number
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : block index
 *
 * Description        : Iterate over the Fee_BlockConfig array,
 *                      find the block index corresponding to the block number.
 * \endverbatim
 *******************************************************************************************************/
#define FEE_START_SEC_CODE_FAST
#include "Fee_MemMap.h"

static uint16 fee_number_to_index(uint16 block_number)
{
    uint16 block_index = FEE_BLOCK_INDEX_DEF;
    uint16 i = 0U;

    /* FEE_BLOCKS_CFG_NUMBER Specifies the block configuration of EB */
    for (i = 0U; i < FEE_BLOCKS_CFG_NUMBER; i++) {
        if (block_number == Fee_BlockConfig[i].blockNumber) {
            block_index = i;
            break;
        }
    }

    return block_index;
}

#define FEE_STOP_SEC_CODE_FAST
#include "Fee_MemMap.h"

/** *****************************************************************************************************
 * \brief This function read data.
 *
 * \verbatim
 * Syntax             : int fee_disk_read(struct fee_dev *fee_dev, Fls_AddressType addr,
 *                                        uint8 *dst, Fls_LengthType size)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      addr - data address
 *                      size - data size
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : dst - Pointer to dst buff
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : read flash data.
 * \endverbatim
 *******************************************************************************************************/
#define FEE_START_SEC_CODE_FAST
#include "Fee_MemMap.h"

static int fee_disk_read(struct fee_dev *fee_dev, Fls_AddressType addr,
                         uint8 *dst, Fls_LengthType size)
{
#if defined(FEE_INFO_DUMP)
    FEE_DEBUG("fee_disk_read addr:%llx size:%llx\n", addr, size);
#endif

    /* Fault error interface */
    fee_read_exception();

    /* Check whether the address meets alignment requirements */
    if (!IS_ALIGNED(dst, fee_dev->disk_mem_align_size)) {
        FEE_ERROR("fee read dst not aligned to disk_mem_align_size\n");
        return FEE_FUN_FAILED;
    }

    if ((!IS_ALIGNED(addr, fee_dev->disk_access_size))
            || (!IS_ALIGNED(size, fee_dev->disk_access_size))) {
        FEE_ERROR("fee read addr or size not aligned to disk_access_size\n");
        return FEE_FUN_FAILED;
    }

    /* Call the actual read interface */
    return Fls_Read(addr, dst, size);
}

#define FEE_STOP_SEC_CODE_FAST
#include "Fee_MemMap.h"

/** *****************************************************************************************************
 * \brief This function write data.
 *
 * \verbatim
 * Syntax             : int fee_disk_write(struct fee_dev *fee_dev, Fls_AddressType addr,
 *                                         const uint8 *src, Fls_LengthType size)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      addr - data address
 *                      src - Pointer to src buff
 *                      size - data size
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : write flash data.
 * \endverbatim
 *******************************************************************************************************/
#define FEE_START_SEC_CODE_FAST
#include "Fee_MemMap.h"

static int fee_disk_write(struct fee_dev *fee_dev, Fls_AddressType addr,
                          const uint8 *src, Fls_LengthType size)
{
#if defined(FEE_INFO_DUMP)
    FEE_DEBUG("fee_disk_write addr:%llx size:%llx\n", addr, size);
#endif

    /* Fault error interface */
    fee_write_exception();

    /* Check whether the address meets alignment requirements */
    if (!IS_ALIGNED(src, fee_dev->disk_mem_align_size)) {
        FEE_ERROR("fee write src not aligned to disk_mem_align_size\n");
        return FEE_FUN_FAILED;
    }

    if ((!IS_ALIGNED(addr, fee_dev->disk_access_size))
            || (!IS_ALIGNED(size, fee_dev->disk_access_size))) {
        FEE_ERROR("fee write addr or size not aligned to disk_access_size\n");
        return FEE_FUN_FAILED;
    }

    /* Call the actual write interface */
    return Fls_Write(addr, src, size);
}

#define FEE_STOP_SEC_CODE_FAST
#include "Fee_MemMap.h"

#define FEE_START_SEC_CODE
#include "Fee_MemMap.h"

/** *****************************************************************************************************
 * \brief This function erase data.
 *
 * \verbatim
 * Syntax             : int fee_disk_erase(struct fee_dev *fee_dev, Fls_AddressType addr,
 *                                         Fls_LengthType size)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      addr - data address
 *                      size - data size
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : erase flash data.
 * \endverbatim
 *******************************************************************************************************/
static int fee_disk_erase(struct fee_dev *fee_dev, Fls_AddressType addr,
                          Fls_LengthType size)
{
#if defined(FEE_INFO_DUMP)
    FEE_DEBUG("fee_disk_erase addr:%llx size:%llx\n", addr, size);
#endif

    /* Fault error interface */
    fee_erase_exception();

    /* Call the actual erase interface */
    return Fls_Erase(addr, size);
}

/** *****************************************************************************************************
 * \brief get page data base on info index.
 *
 * \verbatim
 * Syntax             : int fee_get_sector(struct fee_dev *fee_dev, uint16 page_number,
 *                                         uint32 record_index, uint8 *record_buff)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      page_number - page number
 *                      record_index - info index
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : record_buff - info data buff
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : Split the page according to the info_buff_size,
 *                      and read the info_buff_size data based on the info index.
 * \endverbatim
 *******************************************************************************************************/
static int fee_get_sector(struct fee_dev *fee_dev, uint16 page_number,
                          uint32 record_index, uint8 *record_buff)
{
    return fee_disk_read(fee_dev,
                         fee_dev->page_info[page_number].page_addr + (record_index *
                                 fee_dev->info_buff_size), record_buff, fee_dev->info_buff_size);
}

/** *****************************************************************************************************
 * \brief This function configure page_info.
 *
 * \verbatim
 * Syntax             : int fee_set_page_info(struct fee_dev *fee_dev, uint16 page_number,
 *                                              fee_page_status_t page_status)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      page_number - page number
 *                      page_status - page status
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : configure page_info based on page_number
 * \endverbatim
 *******************************************************************************************************/
int fee_set_page_info(struct fee_dev *fee_dev, uint16 page_number,
                      fee_page_status_t page_status)
{
    struct fee_page_info *page_info = NULL_PTR;
#if (FEE_CHECKSUM_SUPPORTED == STD_ON)
    uint32 info_len = 0U;
#endif

    /* page info buff */
    if (page_number == 0U)
        page_info = (struct fee_page_info *)(unsigned long int)ROUNDUP((unsigned int)page0_info_buf,
                    CONFIG_ARCH_CACHE_LINE);
    else
        page_info = (struct fee_page_info *)(unsigned long int)ROUNDUP((unsigned int)page1_info_buf,
                    CONFIG_ARCH_CACHE_LINE);

    /* config page info */
    Mcal_MemSet(page_info, 0x0, sizeof(struct fee_page_info));
    page_info->page_status = page_status;
#if (FEE_CHECKSUM_SUPPORTED == STD_ON)
    page_info->page_addr = fee_dev->page_info[page_number].page_addr;
    page_info->page_size = fee_dev->page_info[page_number].page_size;
    page_info->swap_count = fee_dev->swap_count;
    info_len = sizeof(page_info->page_addr) + sizeof(page_info->page_size) + sizeof(
                   page_info->swap_count);
    page_info->check_sum = Fee_Crc16((const unsigned char *)&page_info->page_addr,
                                 info_len);
    fee_dev->swap_count++;
#endif

    /* Page information is at the first address of the page */
    return fee_disk_write(fee_dev, fee_dev->page_info[page_number].page_addr,
                          (uint8 *)page_info,
                          sizeof(struct fee_page_info));
}

/** *****************************************************************************************************
 * \brief This function get page_info.
 *
 * \verbatim
 * Syntax             : int fee_get_page_info(struct fee_dev *fee_dev, uint16 page_number)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      page_number - page number
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : get page_info based on page_number
 * \endverbatim
 *******************************************************************************************************/
int fee_get_page_info(struct fee_dev *fee_dev, uint16 page_number)
{
    struct fee_page_info *page_info = NULL_PTR;

    /* page info buff */
    if (page_number == 0U)
        page_info = (struct fee_page_info *)(unsigned long int)ROUNDUP((unsigned int)page0_info_buf,
                    CONFIG_ARCH_CACHE_LINE);
    else
        page_info = (struct fee_page_info *)(unsigned long int)ROUNDUP((unsigned int)page1_info_buf,
                    CONFIG_ARCH_CACHE_LINE);

    /* Page information is at the first address of the page */
    return fee_disk_read(fee_dev, fee_dev->page_info[page_number].page_addr,
                         (uint8 *)page_info,
                         sizeof(struct fee_page_info));
}

/** *****************************************************************************************************
 * \brief This function configure page_status.
 *
 * \verbatim
 * Syntax             : int fee_set_page_status(struct fee_dev *fee_dev, uint16 page_number,
 *                                              fee_page_status_t page_status)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      page_number - page number
 *                      page_status - page status
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : configure page_status based on page_number
 * \endverbatim
 *******************************************************************************************************/
int fee_set_page_status(struct fee_dev *fee_dev, uint16 page_number,
                        fee_page_status_t page_status)
{
    fee_page_status_t *page_status_tmp = NULL_PTR;

    /* page info buff */
    if (page_number == 0U)
        page_status_tmp = (fee_page_status_t *)(unsigned long int)ROUNDUP((unsigned int)page0_info_buf,
                          CONFIG_ARCH_CACHE_LINE);
    else
        page_status_tmp = (fee_page_status_t *)(unsigned long int)ROUNDUP((unsigned int)page1_info_buf,
                          CONFIG_ARCH_CACHE_LINE);

    /* Page information is at the first address of the page */
    *page_status_tmp = page_status;
    return fee_disk_write(fee_dev, fee_dev->page_info[page_number].page_addr,
                          (uint8 *)page_status_tmp,
                          sizeof(fee_page_status_t));
}

/** *****************************************************************************************************
 * \brief This function cheak if it is an erase page.
 *
 * \verbatim
 * Syntax             : boolean fee_check_erase_page_info(struct fee_dev *fee_dev, uint16 page_number)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      page_number - page number
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : TRUE/FALSE
 *
 * Description        : cheak if it is an erase page
 * \endverbatim
 *******************************************************************************************************/
boolean fee_check_erase_page_info(struct fee_dev *fee_dev, uint16 page_number)
{
    struct fee_page_info *page_info = NULL_PTR;

    /* page info buff */
    if (page_number == 0U)
        page_info = (struct fee_page_info *)(unsigned long int)ROUNDUP((unsigned int)page0_info_buf,
                    CONFIG_ARCH_CACHE_LINE);
    else
        page_info = (struct fee_page_info *)(unsigned long int)ROUNDUP((unsigned int)page1_info_buf,
                    CONFIG_ARCH_CACHE_LINE);

    /* check whether the page status is FEE_PAGE_ERASED */
    if (FEE_PAGE_ERASED == page_info->page_status)
        return TRUE;
    else
        return FALSE;
}

/** *****************************************************************************************************
 * \brief This function get page sector data.
 *
 * \verbatim
 * Syntax             : int fee_get_page_sector(struct fee_dev *fee_dev, uint16 page_number,
 *                                              Fls_LengthType page_offset)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      page_number - page number
 *                      page_offset - page address offset
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : get page sector data, length is fixed FEE_SECTOR_BUFF_SIZE
 *                      address is page_offset-FEE_SECTOR_BUFF_SIZE
 *                      buff is fixed page*_sector_buf
 * \endverbatim
 *******************************************************************************************************/
int fee_get_page_sector(struct fee_dev *fee_dev, uint16 page_number,
                        Fls_LengthType page_offset)
{
    uint8 *page_sector = NULL_PTR;
    Fls_AddressType addr = 0U;

    /* page sector buff */
    if (page_number == 0U)
        page_sector = (uint8 *)(unsigned long int)ROUNDUP((unsigned int)page0_sector_buf,
                                      CONFIG_ARCH_CACHE_LINE);
    else
        page_sector = (uint8 *)(unsigned long int)ROUNDUP((unsigned int)page1_sector_buf,
                                      CONFIG_ARCH_CACHE_LINE);

    /* read data */
    addr = fee_dev->page_info[page_number].page_addr + page_offset -
           FEE_SECTOR_BUFF_SIZE;

    return fee_disk_read(fee_dev, addr, (uint8 *)page_sector, FEE_SECTOR_BUFF_SIZE);
}

/** *****************************************************************************************************
 * \brief This function check that the page has been erased clean.
 *
 * \verbatim
 * Syntax             : int fee_sector_status_check(struct fee_dev *fee_dev, uint16 page_number,
 *                                                  Fls_LengthType page_offset)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      page_number - page number
 *                      page_offset - page address offset
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : check that the page has been erased clean, buff is fixed page*_sector_buf
 * \endverbatim
 *******************************************************************************************************/
int fee_sector_status_check(struct fee_dev *fee_dev, uint16 page_number,
                            Fls_LengthType page_offset)
{
    struct fee_page_info *page_info = NULL_PTR;
    uint8 *page_sector = NULL_PTR;

    /* page sector buff */
    if (page_number == 0U) {
        page_info = (struct fee_page_info *)(unsigned long int)ROUNDUP((unsigned int)page0_info_buf,
                    CONFIG_ARCH_CACHE_LINE);
        page_sector = (uint8 *)(unsigned long int)ROUNDUP((unsigned int)page0_sector_buf,
                                      CONFIG_ARCH_CACHE_LINE);
    }
    else {
        page_info = (struct fee_page_info *)(unsigned long int)ROUNDUP((unsigned int)page1_info_buf,
                    CONFIG_ARCH_CACHE_LINE);
        page_sector = (uint8 *)(unsigned long int)ROUNDUP((unsigned int)page1_sector_buf,
                                      CONFIG_ARCH_CACHE_LINE);
    }

    /*
     * If the page status is FEE_PAGE_ERASED, check whether the FEE_SECTOR_BUFF_SIZE data is 0xff.
     * If it is not 0xff, modify the page status to FEE_PAGE_ERASING and erase again
     */
    if (FEE_PAGE_ERASED == page_info->page_status) {
        for (uint32 i = 0U; i < FEE_SECTOR_BUFF_SIZE; i++) {
            if (page_sector[i] != 0xffU) {
                FEE_DEBUG("fee_sector_status_check change page%d FEE_PAGE_ERASED to FEE_PAGE_ERASING\n",
                      page_number);
                page_info->page_status = FEE_PAGE_ERASING;
                break;
            }
        }
    }

    return 0;
}

/** *****************************************************************************************************
 * \brief This function erase all page.
 *
 * \verbatim
 * Syntax             : int fee_erase_all_page(struct fee_dev *fee_dev, uint16 page_number)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      page_number - page number
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : erase all page based on page_number
 * \endverbatim
 *******************************************************************************************************/
int fee_erase_all_page(struct fee_dev *fee_dev, uint16 page_number)
{
    return fee_disk_erase(fee_dev, fee_dev->page_info[page_number].page_addr,
                          fee_dev->page_info[page_number].page_size);
}

/** *****************************************************************************************************
 * \brief This function erase page sector .
 *
 * \verbatim
 * Syntax             : int fee_erase_page_block(struct fee_dev *fee_dev, uint16 page_number,
 *                                               Fls_LengthType page_offset, uint32 erase_size)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      page_number - page number
 *                      page_offset - page offset
 *                      erase_size - erase size
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : erase page sector based on page_number,
 *                      length is erase_size and the address is the end of the page
 * \endverbatim
 *******************************************************************************************************/
int fee_erase_page_block(struct fee_dev *fee_dev, uint16 page_number,
                         Fls_LengthType page_offset, uint32 erase_size)
{
    Fls_AddressType addr = fee_dev->page_info[page_number].page_addr +
                           fee_dev->page_info[page_number].page_size - page_offset - erase_size;

    return fee_disk_erase(fee_dev, addr, erase_size);
}

#if defined(FEE_INFO_DUMP)
/** *****************************************************************************************************
 * \brief This function dump page data .
 *
 * \verbatim
 * Syntax             : int fee_page_dump(struct fee_dev *fee_dev, uint16 page_number)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      page_number - page number
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : displays complete page information based on page_number
 * \endverbatim
 *******************************************************************************************************/
int fee_page_dump(struct fee_dev *fee_dev, uint16 page_number)
{
    int ret = FEE_FUN_OK;
    Fls_LengthType i = 0U;
    uint8 *buff = (uint8 *)(unsigned long int)ROUNDUP((unsigned int)record_info_buff,
                                   CONFIG_ARCH_CACHE_LINE);

    for (i = 0; i < fee_dev->page_info[page_number].page_buff_num; i++) {
        if (fee_get_sector(fee_dev, page_number, i,
                           (uint8 *)buff))
            return FEE_FUN_FAILED;

        FEE_DEBUG("***************Page:%d sector:%d dump*******************\n",
              page_number, i);
        hexdump8_fee_ex(buff, fee_dev->info_buff_size,
                        (uint64)((uint32)buff));
    }

    return ret;
}
#endif

/** *****************************************************************************************************
 * \brief This function set record_info .
 *
 * \verbatim
 * Syntax             : int fee_set_record_info(struct fee_dev *fee_dev, uint16 page_number,
 *                                Fls_LengthType record_index_offset, struct fee_record_info *record_info)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      page_number - page number
 *                      record_index_offset - record info offset
 *                      record_info - record info buff
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : set record_info based on page_number and record_index
 *                      record info at the end of the page, the size is fixed,
 *                      using record_index_offset to calculate the address
 * \endverbatim
 *******************************************************************************************************/
static int fee_set_record_info(struct fee_dev *fee_dev, uint16 page_number,
                               Fls_LengthType record_index_offset, struct fee_record_info *record_info)
{
    /*  */
    Fls_AddressType addr = fee_dev->page_info[page_number].page_addr +
                           fee_dev->page_info[page_number].page_size;
    addr -= (record_index_offset + 1U) * sizeof(struct fee_record_info);
    return fee_disk_write(fee_dev, addr, (uint8 *)record_info,
                          sizeof(struct fee_record_info));
}

/** *****************************************************************************************************
 * \brief This function set record_status .
 *
 * \verbatim
 * Syntax             : int fee_set_record_status(struct fee_dev *fee_dev, uint16 page_number,
 *                                  Fls_LengthType record_index_offset, struct fee_record_info *record_info)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      page_number - page number
 *                      record_index_offset - record info offset
 *                      record_info - record status buff
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : set record_status based on page_number and record_index
 *                      record info at the end of the page, the size is fixed,
 *                      using record_index_offset to calculate the address
 * \endverbatim
 *******************************************************************************************************/
static int fee_set_record_status(struct fee_dev *fee_dev, uint16 page_number,
                                 Fls_LengthType record_index_offset, struct fee_record_info *record_info)
{
    Fls_AddressType addr = fee_dev->page_info[page_number].page_addr +
                           fee_dev->page_info[page_number].page_size;
    addr -= (record_index_offset + 1U) * sizeof(struct fee_record_info);

    return fee_disk_write(fee_dev, addr, (uint8 *)record_info,
                          sizeof(fee_record_status_t) + sizeof(fee_record_sync_t));
}

/** *****************************************************************************************************
 * \brief This function write record data .
 *
 * \verbatim
 * Syntax             : Fls_LengthType fee_write_record_data(struct fee_dev *fee_dev,
 *                          uint16 page_number,
 *                          Fls_LengthType record_data_offset, const uint8 *data_buffer,
 *                          Fls_LengthType length)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      page_number - page number
 *                      record_data_offset - record data offset
 *                      data_buffer - data buff
 *                      length - data len
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : actual write size
 *
 * Description        : write record data based on page_number and record_data_offset
 *                      record data is in the header of the page
 *                      buff address must be aligned with disk_mem_align_size
 *                      address and length must be aligned with disk_access_size
 * \endverbatim
 *******************************************************************************************************/
static Fls_LengthType fee_write_record_data(struct fee_dev *fee_dev,
        uint16 page_number,
        Fls_LengthType record_data_offset, const uint8 *data_buffer,
        Fls_LengthType length)
{
    /* Address offset, start address + page information + block addr + used data offset */
    Fls_LengthType addr = fee_dev->page_info[page_number].page_addr + sizeof(
                              struct fee_page_info) +
                          record_data_offset;

    Fls_LengthType rlen = 0U;
    uint8 *data_buff = NULL_PTR;
    const uint8 *buff = NULL_PTR;

    /*
     * length smaller than disk_access_size,added to disk_access_size
     * Copy data to buffer record_data_buff
     */
    if (length < fee_dev->disk_access_size) {
        data_buff = (uint8 *)(unsigned long int)ROUNDUP((unsigned int)record_data_buff,
                                CONFIG_ARCH_CACHE_LINE);
        rlen = ROUNDUP(length, (uint32)fee_dev->disk_access_size);

        if (data_buffer != data_buff)
            Mcal_MemSet(data_buff, 0xff, rlen);

        /*PRQA S 2998,2996 1*/
        Mcal_MemCpy(data_buff, data_buffer, _MIN(rlen, length));
        buff = (const uint8 *)data_buff;
    }
    else {
        /* mem address aligned, write length down round */
        if (IS_ALIGNED(data_buffer, fee_dev->disk_mem_align_size)) {
            buff = (const uint8 *)data_buffer;
            rlen = ROUNDDOWN(length, (uint32)fee_dev->disk_access_size);
        }
        /*
         * mem address misaligned, copy data to record_data_buff buff
         * actual write size is buffer size and length down round Take a smaller value
         */
        else {
            data_buff = (uint8 *)(unsigned long int)ROUNDUP((unsigned int)record_data_buff,
                                    CONFIG_ARCH_CACHE_LINE);
            rlen = _MIN(ROUNDDOWN(length, (uint32)fee_dev->disk_access_size),
                        fee_dev->data_buff_size);
            Mcal_MemCpy(data_buff, data_buffer, rlen);
            buff = (const uint8 *)data_buff;
        }
    }

    /* Write failed. The return data length is 0 */
    if (fee_disk_write(fee_dev, addr, buff, rlen)) {
        FEE_ERROR("fee_write_record_data page_number %d record_data_offset %lld failure\n",
              page_number, record_data_offset);
        return 0;
    }

    /* returns a smaller length */
    return _MIN(rlen, length);
}

/** *****************************************************************************************************
 * \brief This function read record data .
 *
 * \verbatim
 * Syntax             : Fls_LengthType fee_read_record_data(struct fee_dev *fee_dev,
 *                          uint16 page_number,
 *                          Fls_LengthType record_data_offset, const uint8 *data_buffer,
 *                          Fls_LengthType length, boolean *data_sync)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      page_number - page number
 *                      record_data_offset - record data offset
 *                      length - data len
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : data_buffer - data buff
 *                      data_sync - data sync flag
 *
 * Return value       : actual read size
 *
 * Description        : read record data based on page_number and record_data_offset
 *                      record data is in the header of the page
 *                      buff address must be aligned with disk_mem_align_size
 *                      address and length must be aligned with disk_access_size
 * \endverbatim
 *******************************************************************************************************/
static Fls_LengthType fee_read_record_data(struct fee_dev *fee_dev,
        uint16 page_number,
        Fls_LengthType record_data_offset, uint8 *data_buffer,
        Fls_LengthType length, boolean *data_sync)
{
    /* Address offset, start address + page information + used data offset */
    Fls_LengthType addr = fee_dev->page_info[page_number].page_addr + sizeof(
                              struct fee_page_info) +
                          record_data_offset;

    Fls_LengthType rlen = 0U;
    uint8 *buff = NULL_PTR;

    /* Process the unaligned portion of the address */
    if (!IS_ALIGNED(addr, fee_dev->disk_access_size)) {
        buff = (uint8 *)(unsigned long int)ROUNDUP((unsigned int)record_data_buff,
                                CONFIG_ARCH_CACHE_LINE);
        rlen = _MIN(ROUNDUP(addr, (uint32)fee_dev->disk_access_size) - addr, length);
    }
    /*
     * length smaller than disk_access_size,added to disk_access_size
     * read data to buffer record_data_buff
     */
    else if (length < fee_dev->disk_access_size) {
        buff = (uint8 *)(unsigned long int)ROUNDUP((unsigned int)record_data_buff,
                                CONFIG_ARCH_CACHE_LINE);
        rlen = ROUNDUP(length, (uint32)fee_dev->disk_access_size);
    }
    else {
        /* mem address aligned, read length down round */
        if (IS_ALIGNED(data_buffer, fee_dev->disk_mem_align_size)) {
            buff = (uint8 *)data_buffer;
            rlen = ROUNDDOWN(length, (uint32)fee_dev->disk_access_size);
        }
        /*
         * mem address misaligned, read data to record_data_buff buff
         * actual write size is buffer size and length down round Take a smaller value
         */
        else {
            buff = (uint8 *)(unsigned long int)ROUNDUP((unsigned int)record_data_buff,
                                    CONFIG_ARCH_CACHE_LINE);
            rlen = _MIN(ROUNDDOWN(length, (uint32)fee_dev->disk_access_size),
                        fee_dev->data_buff_size);
        }
    }

    /* read failed. The return data length is 0 */
    if (fee_disk_read(fee_dev, ROUNDDOWN(addr, (uint32)fee_dev->disk_access_size), buff,
                      ROUNDUP(rlen, (uint32)fee_dev->disk_access_size))) {
        FEE_ERROR("fee_read_record_data page_number %d record_data_offset %lld failure\n",
              page_number, record_data_offset);
        return 0;
    }

    /* If reading data into the buffer, set the data sync flag */
    if ((buff != data_buffer) && (NULL_PTR != data_sync)) {
        *data_sync = TRUE;
    }

    /* returns a smaller length */
    return _MIN(rlen, length);
}

#define FEE_STOP_SEC_CODE
#include "Fee_MemMap.h"

/** *****************************************************************************************************
 * \brief This function Check if the block is valid .
 *
 * \verbatim
 * Syntax             : int fee_block_valid_check(struct fee_dev *fee_dev, uint16 block_index)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      block_index - block index
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : TRUE/FALSE
 *
 * Description        : Check if the block is valid
 *                      If the block has not been written (no block record), the block valid flag is not set.
 *                      If a block has been written, the block valid flag is set.
 *                      This information is initialized to determine,
 *                      and configured to the block_status global variable
 * \endverbatim
 *******************************************************************************************************/
#define FEE_START_SEC_CODE_FAST
#include "Fee_MemMap.h"

int fee_block_valid_check(struct fee_dev *fee_dev, uint16 block_index)
{
    return block_status[block_index].valid_flag;
}

#define FEE_STOP_SEC_CODE_FAST
#include "Fee_MemMap.h"

#define FEE_START_SEC_CODE
#include "Fee_MemMap.h"

/** *****************************************************************************************************
 * \brief This function set the block valid .
 *
 * \verbatim
 * Syntax             : int fee_block_valid_set(struct fee_dev *fee_dev, uint16 block_index,
 *                                              boolean flag_value)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      block_index - block index
 *                      flag_value - block valid flag
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : set the block valid
 *                      Set the block_status global variable
 * \endverbatim
 *******************************************************************************************************/
int fee_block_valid_set(struct fee_dev *fee_dev, uint16 block_index,
                        boolean flag_value)
{
    block_status[block_index].valid_flag = flag_value;
    return FEE_FUN_OK;
}

#define FEE_STOP_SEC_CODE
#include "Fee_MemMap.h"

/** *****************************************************************************************************
 * \brief This function Check if the block is invalid .
 *
 * \verbatim
 * Syntax             : int fee_block_invalid_check(struct fee_dev *fee_dev, uint16 block_index)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      block_index - block index
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : TRUE/FALSE
 *
 * Description        : Check if the block is invalid
 *                      Set the block to invalid by setting the record state to FEE_BLOCK_INVALID.
 *                      This information is initialized to determine,
 *                      and configured to the block_status global variable
 * \endverbatim
 *******************************************************************************************************/
#define FEE_START_SEC_CODE_FAST
#include "Fee_MemMap.h"

int fee_block_invalid_check(struct fee_dev *fee_dev, uint16 block_index)
{
    return block_status[block_index].invalid_flag;
}

#define FEE_STOP_SEC_CODE_FAST
#include "Fee_MemMap.h"

#define FEE_START_SEC_CODE
#include "Fee_MemMap.h"

/** *****************************************************************************************************
 * \brief This function set the block invalid .
 *
 * \verbatim
 * Syntax             : int fee_block_invalid_set(struct fee_dev *fee_dev, uint16 block_index,
 *                                              boolean flag_value)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      block_index - block index
 *                      flag_value - block invalid flag
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : set the block invalid
 *                      Set the block_status global variable
 * \endverbatim
 *******************************************************************************************************/
int fee_block_invalid_set(struct fee_dev *fee_dev, uint16 block_index,
                          boolean flag_value)
{
    block_status[block_index].invalid_flag = flag_value;
    return FEE_FUN_OK;
}

/** *****************************************************************************************************
 * \brief  Read the record info configuration.
 *
 * \verbatim
 * Syntax             : int fee_page_record_index_cfg(struct fee_dev *fee_dev)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : Read the record info configuration
 *                      g_sector_index indicates the page sector index
 *                      Read from the end of page, so set g_sector_index to the maximum desired value
 *
 * \endverbatim
 *******************************************************************************************************/
int fee_page_record_index_cfg(struct fee_dev *fee_dev)
{
    uint16 page_number = fee_dev->current_page;
    /* Get the latest record_info_offset(fee_record_info aligned) */
    g_sector_index = fee_dev->page_info[page_number].page_buff_num - 1U;
    return FEE_FUN_OK;
}

/** *****************************************************************************************************
 * \brief  Read the record info.
 *
 * \verbatim
 * Syntax             : int fee_page_get_record_index(struct fee_dev *fee_dev)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : Read the record info
 *                      g_sector_index indicates the page sector index
 *                      buff is record_info_buff
 *
 * \endverbatim
 *******************************************************************************************************/
int fee_page_get_record_index(struct fee_dev *fee_dev)
{
    int ret = FEE_FUN_OK;
    uint16 page_number = fee_dev->current_page;

    /* Get the latest record_info_offset(fee_record_info aligned) */
    struct fee_record_info *record_info = (struct fee_record_info *)(unsigned long int)ROUNDUP((
            unsigned int)record_info_buff, CONFIG_ARCH_CACHE_LINE);
    ret = fee_get_sector(fee_dev, page_number, g_sector_index,
                         (uint8 *)record_info);

    if (ret) {
        FEE_ERROR("fee get record info %d failure\n", g_sector_index);
        return ret;
    }

    return ret;
}

/** *****************************************************************************************************
 * \brief  parse the record info.
 *
 * \verbatim
 * Syntax             : int fee_page_record_index_parse(struct fee_dev *fee_dev, boolean *record_match,
 *                                 boolean *end_match)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : record_match - The last record info index was found
 *                                      TRUE: The search is complete, and the resolution is successful
 *                                      FALSE: Search is not complete.Continue search
 *                      end_match - Traversing the page still does not find the last record index
 *                                      TRUE: Search failed, parsing failed
 *                                      FALSE: Search is not complete.Continue search
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : parse the record info, buff is record_info_buff
 *                      Go through all the record info, configure the initialization information
 *                      find the last record info index
 *
 * \endverbatim
 *******************************************************************************************************/
int fee_page_record_index_parse(struct fee_dev *fee_dev, boolean *record_match,
                                boolean *end_match)
{
    int ret = FEE_FUN_OK;
    int i = 0;
    uint16 page_number = fee_dev->current_page;
    uint16 block_index = 0U;
    /* sector_index_max indicates the maximum index of the page index and is used to calculate record_info_offset */
    Fls_LengthType sector_index_max = fee_dev->page_info[page_number].page_buff_num - 1U;
    /* Cached record info buff */
    struct fee_record_info *record_info = (struct fee_record_info *)(unsigned long int)ROUNDUP((
            unsigned int)record_info_buff, CONFIG_ARCH_CACHE_LINE);
#if (FEE_CHECKSUM_SUPPORTED == STD_ON)
    uint16 record_crc16 = 0U;
    uint32 info_len = 0U;
#endif

    /* record_info Number */
    g_record_index = fee_dev->record_info_num - 1U;
    *record_match = FALSE;
#if (FEE_CHECKSUM_SUPPORTED == STD_ON)
    info_len = sizeof(record_info->record_sync) + sizeof(record_info->record_num) +
               sizeof(record_info->record_len) + sizeof(record_info->record_address);
#endif

    /* The record info store grows upward, so it parses from the tail */
    for (i = g_record_index; i >= 0; i--) {
        /* If the record info is FEE_RECORD_ERASED, the lookup is complete */
        if (record_info[i].record_status == FEE_RECORD_ERASED) {
            *record_match = TRUE;
            fee_dev->record_info_offset = DIVD_NUM(sector_index_max - g_sector_index,
                                                   g_record_index - (uint32)i,
                                                   fee_dev->record_info_num);

            /* first_flag indicates that record has not been written */
            if (fee_dev->record_info_offset == 0U)
                fee_dev->first_flag = TRUE;

            break;
        }
        else {
#if (FEE_CHECKSUM_SUPPORTED == STD_ON)
            /* Check the crc information in the record info to ensure that the data is correct */
            record_crc16 = Fee_Crc16((const unsigned char *)&record_info[i].record_sync,
                                 info_len);

            if (record_info[i].record_crc16 != record_crc16) {
                FEE_ERROR("fee_page_record_index_parse block_number:%d record info crc16:%x != record_crc16:%x\n",
                      record_info[i].record_num, record_info[i].record_crc16, record_crc16);
                continue;
            }

#endif

            /* Valid record info, parsing information */
            if (record_info[i].record_status == FEE_RECORD_VALID
                    || record_info[i].record_status == FEE_BLOCK_INVALID) {
                /* Check block number */
                block_index = fee_number_to_index(record_info[i].record_num);

                if(FEE_BLOCK_INDEX_DEF == block_index) {
                    FEE_ERROR("fee_page_record_index_parse record_num:%d could not find block index\n",
                          record_info[i].record_num);
                    return FEE_FUN_FAILED;
                }

                if (block_status[block_index].block_number != record_info[i].record_num) {
                    FEE_ERROR("fee_page_record_index_parse block_status block_number:%d != record_info record_num:%d\n",
                          block_status[block_index].block_number, record_info[i].record_num);
                    return FEE_FUN_FAILED;
                }

                /* Update block_status */
                block_status[block_index].valid_flag = TRUE;
                block_status[block_index].block_size = record_info[i].record_len;
#if (FEE_CHECKSUM_SUPPORTED == STD_ON)
                block_status[block_index].block_addr[fee_dev->current_page] =
                    record_info[i].record_address;
#else
                block_status[block_index].block_addr[fee_dev->current_page] =
                    fee_dev->record_data_offset;
#endif
                block_status[block_index].block_info_index[fee_dev->current_page] = DIVD_NUM(
                            sector_index_max - g_sector_index,
                            g_record_index - (uint32)i,
                            fee_dev->record_info_num);
#if (FEE_CHECKSUM_SUPPORTED == STD_ON)
                block_status[block_index].record_crc16 = record_info[i].record_crc16;
                block_status[block_index].data_crc16 = record_info[i].data_crc16;
#endif

                /* Update record_status */
                if (record_info[i].record_status == FEE_BLOCK_INVALID)
                    block_status[block_index].invalid_flag = TRUE;
            }

            /* Update data offset */
#if (FEE_CHECKSUM_SUPPORTED == STD_ON)

            if (record_info[i].record_sync == FEE_RECORD_SYNC)
                fee_dev->record_data_offset = record_info[i].record_address + ROUNDUP(
                                                  record_info[i].record_len, (uint32)fee_dev->disk_access_size);

#else

            if (record_info[i].record_sync == FEE_RECORD_SYNC)
                fee_dev->record_data_offset += ROUNDUP(record_info[i].record_len,
                                                       (uint32)fee_dev->disk_access_size);

#endif
        }
    }

    /* Update match information */
    /*PRQA S 2995 5*/
    if (!(*record_match) && g_sector_index > 0U)
        g_sector_index--;
    else if (!(*record_match) && g_sector_index == 0U)
        *end_match = TRUE;

#if defined(FEE_INFO_DUMP)
    FEE_DEBUG("fee_page_record_index_parse record_info_offset %d\n",
          fee_dev->record_info_offset);
    FEE_DEBUG("fee_page_record_index_parse record_data_offset %lld\n",
          fee_dev->record_data_offset);

    for (uint32 block_index_dump = 0; block_index_dump < FEE_BLOCKS_CFG_NUMBER; block_index_dump++)
        FEE_DEBUG("fee_page_record_index_parse block index:%d block_addr %lld\n", block_index_dump,
              block_status[block_index_dump].block_addr[fee_dev->current_page]);

#endif
    return ret;
}

#if (FEE_CHECKSUM_SUPPORTED == STD_ON)

/** *****************************************************************************************************
 * \brief  get the current record_data_offset data.
 *
 * \verbatim
 * Syntax             : int fee_page_get_data_offset(struct fee_dev *fee_dev)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : get the current record_data_offset data
 *                      The address is the offset of record_data_offset
 *                      The length is a fixed data_buff_size
 *                      The buffer is record_data_buff
 *
 * \endverbatim
 *******************************************************************************************************/
int fee_page_get_data_offset(struct fee_dev *fee_dev)
{
    uint16 page_number = fee_dev->current_page;
    Fls_AddressType addr = fee_dev->page_info[page_number].page_addr + sizeof(
                               struct fee_page_info) +
                           fee_dev->record_data_offset;
    uint8 *buff = (uint8 *)(unsigned long int)ROUNDUP((unsigned int)record_data_buff,
                                   CONFIG_ARCH_CACHE_LINE);

    return fee_disk_read(fee_dev, addr, buff, fee_dev->data_buff_size);
}

/** *****************************************************************************************************
 * \brief  check the current record_data_offset data erased.
 *
 * \verbatim
 * Syntax             : int fee_page_check_data_offset(struct fee_dev *fee_dev, boolean *data_check)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : data_check - data erasure check
 *                          TRUE: The data check is complete
 *                          FALSE: The data check not completed
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : check the current record_data_offset data erased
 *                      The address is the offset of record_data_offset
 *                      The length is a fixed data_buff_size
 *                      The buffer is record_data_buff
 *                      If the data is erased, skip the data and add record_data_offset
 *
 * \endverbatim
 *******************************************************************************************************/
int fee_page_check_data_offset(struct fee_dev *fee_dev, boolean *data_check)
{
    int ret = FEE_FUN_OK;
    uint8 *buff = (uint8 *)(unsigned long int)ROUNDUP((unsigned int)record_data_buff,
                                   CONFIG_ARCH_CACHE_LINE);
    Fls_LengthType len = fee_dev->data_buff_size / fee_dev->disk_access_size;
    Fls_LengthType offset = 0U;
    boolean erase_check = TRUE;

    for (offset = 0U; offset < len; offset++) {
        erase_check = TRUE;

        for (uint16 i = 0; i < fee_dev->disk_access_size; i++) {
            if (buff[offset * fee_dev->disk_access_size + i] != 0xffU) {
                erase_check = FALSE;
                break;
            }
        }

        if (erase_check)
            break;
    }

    fee_dev->record_data_offset += offset * fee_dev->disk_access_size;
    *data_check = erase_check;
    FEE_DEBUG("fee_page_check_data_offset:  offset %x len %x\n",
        offset, len);
    FEE_DEBUG("fee_page_check_data_offset:  record_data_offset %x\n",
        fee_dev->record_data_offset);
    FEE_DEBUG("fee_page_check_data_offset:  data_check %x erase_check:%x\n", *data_check,
        erase_check);

    return ret;
}
#endif

/** *****************************************************************************************************
 * \brief  get the current page based on page information.
 *
 * \verbatim
 * Syntax             : int fee_page_active_page(struct fee_dev *fee_dev)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : get the current page based on page information
 *
 *      page0_status/page1_status   FEE_PAGE_ERASED     FEE_PAGE_RECEIVE    FEE_PAGE_ACTIVE     FEE_PAGE_VALID      FEE_PAGE_ERASING
 *              FEE_PAGE_ERASED            0                    ERROR               1                   1               ERROR
 *
 *              FEE_PAGE_RECEIVE         ERROR                  ERROR             ERROR                 1               ERROR
 *
 *              FEE_PAGE_ACTIVE             0                   ERROR             ERROR                 0                  0
 *
 *              FEE_PAGE_VALID              0                      0                 1                ERROR             ERROR
 *
 *              FEE_PAGE_ERASING         ERROR                  ERROR                1                ERROR             ERROR
 *
 * \endverbatim
 *******************************************************************************************************/
int fee_page_active_page(struct fee_dev *fee_dev)
{
    int ret = FEE_FUN_OK;
    /* page information */
    fee_page_status_t page0_status = *(fee_page_status_t *)(unsigned long int)ROUNDUP((
                                         unsigned int)page0_info_buf, CONFIG_ARCH_CACHE_LINE);
    fee_page_status_t page1_status = *(fee_page_status_t *)(unsigned long int)ROUNDUP((
                                         unsigned int)page1_info_buf, CONFIG_ARCH_CACHE_LINE);

    FEE_DEBUG("set current page:  page0_status %x page1_status %x\n",
        page0_status, page1_status);

    switch (page0_status) {
        case FEE_PAGE_ERASED:
            switch (page1_status) {
                case FEE_PAGE_ERASED:
                    fee_dev->first_flag = TRUE;
                    fee_dev->current_page = 0U;
                    break;

                case FEE_PAGE_ACTIVE:
                case FEE_PAGE_VALID:
                    fee_dev->current_page = 1U;
                    break;

                default:
                    goto error;
            }

            break;

        case FEE_PAGE_RECEIVE:
            switch (page1_status) {
                case FEE_PAGE_VALID:
                    fee_dev->current_page = 1U;
                    break;

                default:
                    goto error;
            }

            break;

        case FEE_PAGE_ACTIVE:
            switch (page1_status) {
                case FEE_PAGE_ERASED:
                case FEE_PAGE_VALID:
                case FEE_PAGE_ERASING:
                    fee_dev->current_page = 0U;
                    break;

                default:
                    fee_dev->current_page = 0U;
                    goto active_error_status;
            }

            break;

        case FEE_PAGE_VALID:
            switch (page1_status) {
                case FEE_PAGE_ERASED:
                case FEE_PAGE_RECEIVE:
                    fee_dev->current_page = 0U;
                    break;

                case FEE_PAGE_ACTIVE:
                    fee_dev->current_page = 1U;
                    break;

                default:
                    goto error;
            }

            break;

        case FEE_PAGE_ERASING:
            switch (page1_status) {
                case FEE_PAGE_ACTIVE:
                    fee_dev->current_page = 1U;
                    break;

                default:
                    goto error;
            }

            break;

        default:
            if (FEE_PAGE_ACTIVE == page1_status) {
                fee_dev->current_page = 1U;
                goto active_error_status;
            }
            else {
                goto error;
            }
    }

    return ret;

    /* If a page is in the FEE_PAGE_ACTIVE state, the page is forced to be active */
active_error_status:
    FEE_DEBUG("fee_page_set_two page0_status %x page1_status %x, change error_status to FEE_PAGE_ERASING\n",
          page0_status, page1_status);
    return ret;

error:
    FEE_ERROR("fee_page_set_two page0_status %x page1_status %x failure\n",
          page0_status, page1_status);
    return FEE_FUN_FAILED;
}

/** *****************************************************************************************************
 * \brief  Page state information detection.
 *
 * \verbatim
 * Syntax             : int fee_page_check_status(struct fee_dev *fee_dev, fee_page_job *page_job,
                          uint16 *fee_active_page, uint16 *fee_erase_page)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : page_job - page processing jobs
 *                      fee_active_page - active_page number
 *                      fee_erase_page - erase_page number
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : Page state information detection
 *
 *      page0_status/page1_status   FEE_PAGE_ERASED     FEE_PAGE_RECEIVE    FEE_PAGE_ACTIVE     FEE_PAGE_VALID      FEE_PAGE_ERASING
 *              FEE_PAGE_ERASED     FEE_PAGE_FORMAT           ERROR         FEE_PAGE_NORMAL     FEE_PAGE_SWAP          ERROR
 *
 *              FEE_PAGE_RECEIVE         ERROR                ERROR             ERROR        FEE_PAGE_ERASE_SWAP       ERROR
 *
 *              FEE_PAGE_ACTIVE     FEE_PAGE_NORMAL           ERROR             ERROR           FEE_PAGE_ERASE        FEE_PAGE_ERASE
 *
 *              FEE_PAGE_VALID      FEE_PAGE_SWAP      FEE_PAGE_ERASE_SWAP   FEE_PAGE_ERASE          ERROR             ERROR
 *
 *              FEE_PAGE_ERASING         ERROR                  ERROR        FEE_PAGE_ERASE          ERROR             ERROR
 *
 * \endverbatim
 *******************************************************************************************************/
int fee_page_check_status(struct fee_dev *fee_dev, fee_page_job *page_job,
                          uint16 *fee_active_page, uint16 *fee_erase_page)
{
    int ret = FEE_FUN_OK;
    /* page information */
    fee_page_status_t page0_status = *(fee_page_status_t *)(unsigned long int)ROUNDUP((
                                         unsigned int)page0_info_buf, CONFIG_ARCH_CACHE_LINE);
    fee_page_status_t page1_status = *(fee_page_status_t *)(unsigned long int)ROUNDUP((
                                         unsigned int)page1_info_buf, CONFIG_ARCH_CACHE_LINE);

    FEE_DEBUG("check current page:  page0_status %x page1_status %x\n",
        page0_status, page1_status);

    switch (page0_status) {
        case FEE_PAGE_ERASED:
            switch (page1_status) {
                case FEE_PAGE_ERASED:
                    FEE_DEBUG("fee dev is initialized for the first time,fee_format\n");
                    /* Power on for the first time */
                    g_active_page = 0U;
                    g_erase_page = 1U;
                    *fee_active_page = g_active_page;
                    *fee_erase_page = g_erase_page;
                    *page_job = FEE_PAGE_FORMAT;
                    break;

                case FEE_PAGE_ACTIVE:
                    FEE_DEBUG("fee page information is normal\n");
                    /* Normal boot */
                    g_active_page = 1U;
                    g_erase_page = 0U;
                    *fee_active_page = g_active_page;
                    *fee_erase_page = g_erase_page;
                    *page_job = FEE_PAGE_NORMAL;
                    break;

                case FEE_PAGE_VALID:
                    /* Page1 data is exchanged to Page0 */
                    FEE_DEBUG("fee page1 data is full, exchange data to page0\n");
                    g_active_page = 1U;
                    g_erase_page = 0U;
                    *fee_active_page = g_active_page;
                    *fee_erase_page = g_erase_page;
                    *page_job = FEE_PAGE_SWAP;
                    break;

                default:
                    goto error;
            }

            break;

        case FEE_PAGE_RECEIVE:
            switch (page1_status) {
                case FEE_PAGE_VALID:
                    /* Page1 data is exchanged to Page0 */
                    FEE_DEBUG("fee page1 data is full, erase page0 & exchange data to page0\n");
                    g_active_page = 1U;
                    g_erase_page = 0U;
                    *fee_active_page = g_active_page;
                    *fee_erase_page = g_erase_page;
                    *page_job = FEE_PAGE_ERASE_SWAP;
                    break;

                default:
                    goto error;
            }

            break;

        case FEE_PAGE_ACTIVE:
            switch (page1_status) {
                case FEE_PAGE_ERASED:
                    FEE_DEBUG( "fee page information is normal\n");
                    /* Normal boot */
                    g_active_page = 0U;
                    g_erase_page = 1U;
                    *fee_active_page = g_active_page;
                    *fee_erase_page = g_erase_page;
                    *page_job = FEE_PAGE_NORMAL;
                    break;

                case FEE_PAGE_VALID:
                case FEE_PAGE_ERASING:
                    FEE_DEBUG("fee erase page1\n");
                    g_active_page = 0U;
                    g_erase_page = 1U;
                    *fee_active_page = g_active_page;
                    *fee_erase_page = g_erase_page;
                    *page_job = FEE_PAGE_ERASE;
                    break;

                default:
                    FEE_DEBUG("fee erase page1\n");
                    g_active_page = 0U;
                    g_erase_page = 1U;
                    *fee_active_page = g_active_page;
                    *fee_erase_page = g_erase_page;
                    *page_job = FEE_PAGE_ERASE;
                    goto active_error_status;
            }

            break;

        case FEE_PAGE_VALID:
            switch (page1_status) {
                case FEE_PAGE_ERASED:
                    FEE_DEBUG( "fee page0 data is full, exchange data to page1\n");
                    /* Page0 Data is exchanged to page1 */
                    g_active_page = 0U;
                    g_erase_page = 1U;
                    *fee_active_page = g_active_page;
                    *fee_erase_page = g_erase_page;
                    *page_job = FEE_PAGE_SWAP;
                    break;

                case FEE_PAGE_RECEIVE:
                    /* Page0 Data is exchanged to page1 */
                    FEE_DEBUG("fee page0 data is full, erase page1 & exchange data to page1\n");
                    g_active_page = 0U;
                    g_erase_page = 1U;
                    *fee_active_page = g_active_page;
                    *fee_erase_page = g_erase_page;
                    *page_job = FEE_PAGE_ERASE_SWAP;
                    break;

                case FEE_PAGE_ACTIVE:
                    FEE_DEBUG("fee erase page0\n");
                    g_active_page = 1U;
                    g_erase_page = 0U;
                    *fee_active_page = g_active_page;
                    *fee_erase_page = g_erase_page;
                    *page_job = FEE_PAGE_ERASE;
                    break;

                default:
                    goto error;
            }

            break;

        case FEE_PAGE_ERASING:
            switch (page1_status) {
                case FEE_PAGE_ACTIVE:
                    FEE_DEBUG("fee erase page0\n");
                    /* Erase the page0 */
                    g_active_page = 1U;
                    g_erase_page = 0U;
                    *fee_active_page = g_active_page;
                    *fee_erase_page = g_erase_page;
                    *page_job = FEE_PAGE_ERASE;
                    break;

                default:
                    goto error;
            }

            break;

        default:
            if (FEE_PAGE_ACTIVE == page1_status) {
                FEE_DEBUG("fee erase page0\n");
                g_active_page = 1U;
                g_erase_page = 0U;
                *fee_active_page = g_active_page;
                *fee_erase_page = g_erase_page;
                *page_job = FEE_PAGE_ERASE;
                goto active_error_status;
            }
            else {
                goto error;
            }
    }

    return ret;

    /* If a page is in the FEE_PAGE_ACTIVE state, The other page state is forced to FEE_PAGE_ERASING */
active_error_status:
    FEE_DEBUG("fee_page_check_status page0_status %x page1_status %x, change error_status to FEE_PAGE_ERASING\n",
          page0_status, page1_status);
    return ret;

error:
    *page_job = FEE_PAGE_ERROR;
    FEE_ERROR("page0_status %x page1_status %x failure\n",
          page0_status, page1_status);
    return FEE_FUN_FAILED;
}

#if (FEE_CHECKSUM_SUPPORTED == STD_ON)
/** *****************************************************************************************************
 * \brief  Check that the page info data is valid.
 *
 * \verbatim
 * Syntax             : int fee_page_info_check(struct fee_dev *fee_dev, uint16 page_number)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      page_number - page number
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : Check that the page info data is valid
 *
 * \endverbatim
 *******************************************************************************************************/
int fee_page_info_check(struct fee_dev *fee_dev, uint16 page_number)
{
    struct fee_page_info *page_info = NULL_PTR;
    uint32 info_len = 0U;
    uint16 info_crc16 = 0U;

    /* page info buff */
    if (page_number == 0U)
        page_info = (struct fee_page_info *)(unsigned long int)ROUNDUP((unsigned int)page0_info_buf,
                    CONFIG_ARCH_CACHE_LINE);
    else
        page_info = (struct fee_page_info *)(unsigned long int)ROUNDUP((unsigned int)page1_info_buf,
                    CONFIG_ARCH_CACHE_LINE);

    /* Calculate and check crc */
    info_len = sizeof(page_info->page_addr) + sizeof(page_info->page_size) + sizeof(
                   page_info->swap_count);
    info_crc16 = Fee_Crc16((const unsigned char *)&page_info->page_addr, info_len);

    /* Check whether the EB configuration matches the actual Fee info */
    if (info_crc16 != page_info->check_sum) {
        FEE_ERROR("fee page info crc16 error, info_crc16:%d check_sum:%d page_addr:0x%x page_size:0x%x swap_count:%d\n",
              info_crc16, page_info->check_sum, page_info->page_addr, page_info->page_size,
              page_info->swap_count);
        goto error;
    }

    if (page_info->page_addr != fee_dev->page_info[page_number].page_addr) {
        FEE_ERROR("fee page info page_addr error, page_info page_addr:0x%x fee_dev page_addr:0x%x\n",
              page_info->page_addr, fee_dev->page_info[page_number].page_addr);
        goto error;
    }

    if (page_info->page_size != fee_dev->page_info[page_number].page_size) {
        FEE_ERROR("fee page info page_size error, page_info page_size:0x%x fee_dev page_size:0x%x\n",
              page_info->page_size, fee_dev->page_info[page_number].page_size);
        goto error;
    }

    fee_dev->swap_count = page_info->swap_count + 1U;
    return FEE_FUN_OK;
error:
    return FEE_FUN_FAILED;
}
#endif

/** *****************************************************************************************************
 * \brief  Initial configuration.
 *
 * \verbatim
 * Syntax             : int fee_config(struct fee_dev *fee_dev)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : Initialization parameter
 *
 * \endverbatim
 *******************************************************************************************************/
int fee_config(struct fee_dev *fee_dev)
{
    int ret = FEE_FUN_OK;
    uint16 i = 0U;
    /* Configure basic page information */
    fee_dev->page_number = FEE_PAGE_NUMBER;
    fee_dev->disk_access_size = FEE_ACCESS_BYTE;

    fee_dev->data_buff_size = FEE_DATA_CACHE_SIZE;
    fee_dev->info_buff_size = FEE_INFO_CACHE_SIZE;

    /*PRQA S 1573,2995,2992,2996,2880 6 */
    if ((fee_dev->data_buff_size == 0) || (fee_dev->info_buff_size == 0)) {
        FEE_ERROR("fee data buff_size %x or record_info buff_size %x is zero\n",
              fee_dev->data_buff_size, fee_dev->info_buff_size);
        goto error;
    }

    /*PRQA S 1573,2995,2992,2996,2880 6 */
    if (!IS_ALIGNED(fee_dev->data_buff_size, fee_dev->disk_mem_align_size) ||
            !IS_ALIGNED(fee_dev->info_buff_size, fee_dev->disk_mem_align_size)) {
        FEE_ERROR("fee data buff_size %x or record_info buff_size %x not aligned to disk mem_align size %x\n",
              fee_dev->data_buff_size, fee_dev->info_buff_size, fee_dev->disk_mem_align_size);
        goto error;
    }

    /*PRQA S 1573,2995,2992,2996,2880 6 */
    /* Verify that the Record INFO is aligned to the sector */
    if (!IS_ALIGNED(fee_dev->info_buff_size, sizeof(struct fee_record_info))) {
        FEE_ERROR("fee record_info buff_size %x not aligned to fee_record_info size %x\n",
              fee_dev->info_buff_size, sizeof(struct fee_record_info));
        goto error;
    }

    fee_dev->record_info_num = fee_dev->info_buff_size / sizeof(
                                   struct fee_record_info);

    for (i = 0U; i < fee_dev->page_number; i++) {

        /* Verify that the Record INFO is aligned to the sector */
        if (!IS_ALIGNED(fee_dev->page_info[i].page_size, fee_dev->info_buff_size)) {
            FEE_ERROR("fee page_size %llx not aligned to info_buff_size %x\n",
                  fee_dev->page_info[i].page_size, fee_dev->info_buff_size);
            goto error;
        }

        fee_dev->page_info[i].page_buff_num = fee_dev->page_info[i].page_size /
                                              fee_dev->info_buff_size;
        FEE_DEBUG("page %d addr:%llx size:%llx page_buff_num:%x\n",
            i, fee_dev->page_info[i].page_addr, fee_dev->page_info[i].page_size,
            fee_dev->page_info[i].page_buff_num);
    }

    return ret;

error:
    return FEE_FUN_FAILED;
}

/** *****************************************************************************************************
 * \brief  first initial configuration.
 *
 * \verbatim
 * Syntax             : int fee_first_cfg(struct fee_dev *fee_dev)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : first initialization parameter
 *
 * \endverbatim
 *******************************************************************************************************/
int fee_first_cfg(struct fee_dev *fee_dev)
{
    int ret = FEE_FUN_OK;
    /* Configure basic page information */
    fee_dev->record_info_offset = 0U;
    fee_dev->record_data_offset = 0U;
#if (FEE_CHECKSUM_SUPPORTED == STD_ON)
    fee_dev->swap_count = 0U;
#endif
    return ret;
}

#define FEE_STOP_SEC_CODE
#include "Fee_MemMap.h"

/** *****************************************************************************************************
 * \brief  Check the free page capacity.
 *
 * \verbatim
 * Syntax             : int fee_page_check_size(struct fee_dev *fee_dev, uint16 page_number,
 *                                Fls_LengthType length)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      page_number - page number
 *                      length - wirte data len
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : Check whether the free capacity of the page is sufficient for writing data
 *
 * \endverbatim
 *******************************************************************************************************/
#define FEE_START_SEC_CODE_FAST
#include "Fee_MemMap.h"

static int fee_page_check_size(struct fee_dev *fee_dev, uint16 page_number,
                               Fls_LengthType length)
{
    /* Fee Residual space detection */
    /* One more record info space must be reserved for initial use of the record index offset */
    Fls_LengthType used_size = sizeof(struct fee_page_info) +
                               fee_dev->record_data_offset + (fee_dev->record_info_offset * sizeof(
                                           struct fee_record_info) + sizeof(struct fee_record_info));

    if (fee_dev->page_info[page_number].page_size < used_size + length)
        return FALSE;
    else
        return TRUE;
}

#define FEE_STOP_SEC_CODE_FAST
#include "Fee_MemMap.h"

#define FEE_START_SEC_CODE
#include "Fee_MemMap.h"

/** *****************************************************************************************************
 * \brief  Write block check.
 *
 * \verbatim
 * Syntax             : int fee_write_block_check(struct fee_dev *fee_dev, uint16 block_number,
                          const uint8 *data_buffer, uint16 length, boolean immediate_data, boolean *page_swap)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      page_number - page number
 *                      data_buffer - data buff
 *                      length - block length
 *                      immediate_data - immediate block
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : page_swap - Whether the write causes page switch
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : Check whether block is supported by EB
 *                      whether block is invalid, and whether page switching is caused by writing data
 *
 * \endverbatim
 *******************************************************************************************************/
int fee_write_block_check(struct fee_dev *fee_dev, uint16 block_number,
                          const uint8 *data_buffer, uint16 length, boolean immediate_data, boolean *page_swap)
{
    int ret = FEE_FUN_OK;
    Fls_LengthType rlen = 0U;
    uint16 block_index = fee_number_to_index(block_number);

    /* Check whether block is supported by EB */
    if(FEE_BLOCK_INDEX_DEF == block_index) {
        FEE_ERROR("fee_write_block_check block_number:%d could not find block index\n",
              block_number);
        return FEE_FUN_FAILED;
    }

    /* whether block is invalid */
    if (fee_block_invalid_check(fee_dev, block_index)) {
        FEE_ERROR("fee block invalid block_number:%d\n", block_number);
        return FEE_FUN_FAILED;
    }

    /* whether page switching is caused by writing data */
    if (immediate_data)
        rlen = length + sizeof(struct fee_record_info);
    else
        rlen = length + sizeof(struct fee_record_info) + fee_dev->disk_reserved_size;

    if (!fee_page_check_size(fee_dev, fee_dev->current_page, rlen)) {
        *page_swap = TRUE;
    }

    return ret;
}

/** *****************************************************************************************************
 * \brief  Save the block status information.
 *
 * \verbatim
 * Syntax             : int fee_block_status_backup(struct fee_dev *fee_dev, uint16 block_index)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      block_index - block index
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : Save the block status information
 *                      If the block fails to be written, the block status is restored
 *
 * \endverbatim
 *******************************************************************************************************/
int fee_block_status_backup(struct fee_dev *fee_dev, uint16 block_index)
{
    int ret = FEE_FUN_OK;

    block_status_backup[block_index].block_number =
        block_status[block_index].block_number;
    block_status_backup[block_index].block_size =
        block_status[block_index].block_size;
    block_status_backup[block_index].block_addr[fee_dev->current_page] =
        block_status[block_index].block_addr[fee_dev->current_page];
    block_status_backup[block_index].block_info_index[fee_dev->current_page] =
        block_status[block_index].block_info_index[fee_dev->current_page];

#if (FEE_CHECKSUM_SUPPORTED == STD_ON)
    block_status_backup[block_index].record_crc16 =
        block_status[block_index].record_crc16;
    block_status_backup[block_index].data_crc16 =
        block_status[block_index].data_crc16;
    block_status_backup[block_index].checksum_error =
        block_status[block_index].checksum_error;
#endif

    block_status_backup[block_index].valid_flag =
        block_status[block_index].valid_flag;
    block_status_backup[block_index].invalid_flag =
        block_status[block_index].invalid_flag;

    return ret;
}

/** *****************************************************************************************************
 * \brief  Recover the block status information.
 *
 * \verbatim
 * Syntax             : int fee_block_status_recover(struct fee_dev *fee_dev, uint16 block_index)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      block_index - block index
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : Recover the block status information
 *                      If the block fails to be written, the block status is restored
 *
 * \endverbatim
 *******************************************************************************************************/
int fee_block_status_recover(struct fee_dev *fee_dev, uint16 block_index)
{
    int ret = FEE_FUN_OK;

    block_status[block_index].block_number =
        block_status_backup[block_index].block_number;
    block_status[block_index].block_size =
        block_status_backup[block_index].block_size;
    block_status[block_index].block_addr[fee_dev->current_page] =
        block_status_backup[block_index].block_addr[fee_dev->current_page];
    block_status[block_index].block_info_index[fee_dev->current_page] =
        block_status_backup[block_index].block_info_index[fee_dev->current_page];

#if (FEE_CHECKSUM_SUPPORTED == STD_ON)
    block_status[block_index].record_crc16 =
        block_status_backup[block_index].record_crc16;
    block_status[block_index].data_crc16 =
        block_status_backup[block_index].data_crc16;
    block_status[block_index].checksum_error =
        block_status_backup[block_index].checksum_error;
#endif

    block_status[block_index].valid_flag =
        block_status_backup[block_index].valid_flag;
    block_status[block_index].invalid_flag =
        block_status_backup[block_index].invalid_flag;

    return ret;
}

/** *****************************************************************************************************
 * \brief  Writes update configuration status information.
 *
 * \verbatim
 * Syntax             : int fee_write_cfg(struct fee_dev *fee_dev, uint16 block_number)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      block_number - block number
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : Writes update configuration status information
 *
 * \endverbatim
 *******************************************************************************************************/
int fee_write_cfg(struct fee_dev *fee_dev, uint16 block_number)
{
    int ret = FEE_FUN_OK;
    uint16 block_index = fee_number_to_index(block_number);

    fee_block_status_backup(fee_dev, block_index);

    fee_dev->record_info_offset_backup = fee_dev->record_info_offset;
    fee_dev->record_data_offset_backup = fee_dev->record_data_offset;

#if defined(FEE_INFO_DUMP)
    FEE_DEBUG("fee_write_cfg block_number:%d record_info_offset:%d record_data_offset:%d\n",
        block_number, fee_dev->record_info_offset, fee_dev->record_data_offset);
#endif
    return ret;
}

/** *****************************************************************************************************
 * \brief  Write failed. Restore the status information.
 *
 * \verbatim
 * Syntax             : int fee_write_recover(struct fee_dev *fee_dev, uint16 block_number,
 *                                            uint16 length, boolean offset_update)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      block_number - block number
 *                      length - block length
 *                      offset_update - Whether the offset data has been updated
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : Write failed. Restore the status information
 *
 * \endverbatim
 *******************************************************************************************************/
int fee_write_recover(struct fee_dev *fee_dev, uint16 block_number,
                      uint16 length, boolean offset_update)
{
    int ret = FEE_FUN_OK;
    uint16 block_index = 0;

    block_index = fee_number_to_index(block_number);
    fee_block_status_recover(fee_dev, block_index);

    if (offset_update) {
        fee_dev->record_info_offset = fee_dev->record_info_offset_backup + 1;
        fee_dev->record_data_offset = fee_dev->record_data_offset_backup + ROUNDUP(
                                          length, (uint32)fee_dev->disk_access_size);
    }
    else {
        fee_dev->record_info_offset = fee_dev->record_info_offset_backup;
        fee_dev->record_data_offset = fee_dev->record_data_offset_backup;
    }

#if defined(FEE_INFO_DUMP)
    FEE_DEBUG("fee_write_cfg block_number:%d record_info_offset:%d record_data_offset:%d\n",
        block_number, fee_dev->record_info_offset, fee_dev->record_data_offset);
#endif
    return ret;
}

#if (FEE_CHECKSUM_SUPPORTED == STD_ON)
/** *****************************************************************************************************
 * \brief  Writes the block's record info.
 *
 * \verbatim
 * Syntax             : int fee_write_block_info(struct fee_dev *fee_dev, uint16 block_number,
 *                                   const uint8 *data_buffer, uint16 length, fee_record_status_t record_status,
 *                                   uint16 data_crc16)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      block_number - block number
 *                      data_buffer - data buff
 *                      length - block length
 *                      record_status - record status
 *                      data_crc16 - data crc value
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : Writes the block's record info
 *
 * \endverbatim
 *******************************************************************************************************/
int fee_write_block_info(struct fee_dev *fee_dev, uint16 block_number,
                         const uint8 *data_buffer, uint16 length, fee_record_status_t record_status,
                         uint16 data_crc16)
{
    int ret = FEE_FUN_OK;
    uint32 info_len = 0U;
    uint16 block_index = fee_number_to_index(block_number);
    struct fee_record_info *record_info = NULL_PTR;

    /* Check block index */
    if(FEE_BLOCK_INDEX_DEF == block_index) {
        FEE_ERROR("fee_write_block_info block_number:%d could not find block index\n",
              block_number);
        return FEE_FUN_FAILED;
    }

    /* Configuring record info */
    record_info = (struct fee_record_info *)(unsigned long int)ROUNDUP((
                unsigned int)block_info_buff, CONFIG_ARCH_CACHE_LINE);
    record_info->record_status = record_status;
    record_info->record_sync = FEE_RECORD_SYNC;
    record_info->record_num = block_number;
    record_info->record_len = length;
    record_info->record_address = fee_dev->record_data_offset;
    info_len = sizeof(record_info->record_sync) + sizeof(record_info->record_num) +
               sizeof(record_info->record_len) + sizeof(record_info->record_address);
    record_info->record_crc16 = Fee_Crc16((const unsigned char *)
                                      &record_info->record_sync, info_len);
    record_info->data_crc16 = data_crc16;

    /* write record info */
    ret = fee_set_record_info(fee_dev, fee_dev->current_page,
                              fee_dev->record_info_offset,
                              record_info);

    if (ret) {
        FEE_ERROR("fee_block_write set_record_info block_number %d failure\n",
              block_number);
        return ret;
    }

    /* Update block status information */
    block_status[block_index].block_info_index[fee_dev->current_page] =
        fee_dev->record_info_offset;
    block_status[block_index].block_size = length;
    block_status[block_index].record_crc16 = record_info->record_crc16;
    block_status[block_index].data_crc16 = record_info->data_crc16;

    if (block_status[block_index].checksum_error) {
        block_status[block_index].checksum_error = FALSE;
    }

    fee_dev->record_info_offset++;
#if defined(FEE_INFO_DUMP)
    FEE_DEBUG("fee_write_block_info block_index:%d record_info_offset %d data_crc16:%x\n",
          block_index, fee_dev->record_info_offset, block_status[block_index].data_crc16);
#endif
    return ret;
}
#else
/** *****************************************************************************************************
 * \brief  Writes the block's record info.
 *
 * \verbatim
 * Syntax             : int fee_write_block_info(struct fee_dev *fee_dev, uint16 block_number,
 *                          const uint8 *data_buffer, uint16 length, fee_record_status_t record_status)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      block_number - block number
 *                      data_buffer - data buff
 *                      length - block length
 *                      record_status - record status
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : Writes the block's record info
 *
 * \endverbatim
 *******************************************************************************************************/
int fee_write_block_info(struct fee_dev *fee_dev, uint16 block_number,
                         const uint8 *data_buffer, uint16 length, fee_record_status_t record_status)
{
    int ret = FEE_FUN_OK;
    uint16 block_index = fee_number_to_index(block_number);
    struct fee_record_info *record_info = NULL_PTR;

    /* Check block index */
    if(FEE_BLOCK_INDEX_DEF == block_index) {
        FEE_ERROR("fee_write_block_info block_number:%d could not find block index\n",
              block_number);
        return FEE_FUN_FAILED;
    }

    /* Configuring record info */
    record_info = (struct fee_record_info *)(unsigned long int)ROUNDUP((
            unsigned int)block_info_buff, CONFIG_ARCH_CACHE_LINE);
    record_info->record_status = record_status;
    record_info->record_sync = FEE_RECORD_SYNC;
    record_info->record_num = block_number;
    record_info->record_len = length;

    /* write record info */
    ret = fee_set_record_info(fee_dev, fee_dev->current_page,
                              fee_dev->record_info_offset,
                              record_info);

    if (ret) {
        FEE_ERROR("fee_block_write set_record_info block_number %d failure\n",
              block_number);
        return ret;
    }

    /* Update block status information */
    block_status[block_index].block_info_index[fee_dev->current_page] =
        fee_dev->record_info_offset;
    block_status[block_index].block_size = length;
    fee_dev->record_info_offset++;
#if defined(FEE_INFO_DUMP)
    FEE_DEBUG("fee_write_block_info record_info_offset %d\n",
          fee_dev->record_info_offset);
#endif
    return ret;
}
#endif

/** *****************************************************************************************************
 * \brief  Synchronize block info.
 *
 * \verbatim
 * Syntax             : int fee_write_block_info_sync(struct fee_dev *fee_dev, uint16 block_number,
 *                               uint16 length)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      block_number - block number
 *                      length - block length
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : Synchronize block info
 *
 * \endverbatim
 *******************************************************************************************************/
int fee_write_block_info_sync(struct fee_dev *fee_dev, uint16 block_number,
                              uint16 length)
{
    fee_dev->record_data_offset_ops = fee_dev->record_data_offset;
    fee_dev->record_data_offset_backup = fee_dev->record_data_offset;
    fee_dev->record_data_offset += ROUNDUP(length, (uint32)fee_dev->disk_access_size);
#if defined(FEE_INFO_DUMP)
    FEE_DEBUG("fee_write_block_info_sync record_data_offset %d\n",
          fee_dev->record_data_offset);
#endif
    return FEE_FUN_OK;
}

/** *****************************************************************************************************
 * \brief  Writes block data.
 *
 * \verbatim
 * Syntax             : uint16 fee_write_block_data(struct fee_dev *fee_dev, uint16 block_number,
 *                             const uint8 *data_buffer, uint16 length)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      block_number - block number
 *                      data_buffer - data buff
 *                      length - block length
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : Writes block data, generate a record of that write
 *
 * \endverbatim
 *******************************************************************************************************/
uint16 fee_write_block_data(struct fee_dev *fee_dev, uint16 block_number,
                            const uint8 *data_buffer, uint16 length)
{
    uint16 rlen = (uint16)fee_write_record_data(fee_dev, fee_dev->current_page,
                          fee_dev->record_data_offset_ops, data_buffer, length);

    if (rlen)
        fee_dev->record_data_offset_ops += ROUNDUP(rlen, (uint32)fee_dev->disk_access_size);

    return rlen;
}

/** *****************************************************************************************************
 * \brief  Synchronize block data.
 *
 * \verbatim
 * Syntax             : int fee_write_block_data_sync(struct fee_dev *fee_dev, uint16 block_number,
 *                               uint16 length)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      block_number - block number
 *                      length - block length
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : Synchronize block data
 *
 * \endverbatim
 *******************************************************************************************************/
int fee_write_block_data_sync(struct fee_dev *fee_dev, uint16 block_number,
                              uint16 length)
{
    uint16 block_index = fee_number_to_index(block_number);

    if(FEE_BLOCK_INDEX_DEF == block_index) {
        FEE_ERROR("fee_write_block_data_sync block_number:%d could not find block index\n",
              block_number);
        return FEE_FUN_FAILED;
    }

    block_status[block_index].block_addr[fee_dev->current_page] =
        fee_dev->record_data_offset_backup;
#if defined(FEE_INFO_DUMP)
    FEE_DEBUG("fee_write_block_data_sync block_addr %d\n",
          block_status[block_index].block_addr[fee_dev->current_page]);
#endif
    return FEE_FUN_OK;
}

/** *****************************************************************************************************
 * \brief  Update the record info status to active.
 *
 * \verbatim
 * Syntax             : int fee_write_block_active(struct fee_dev *fee_dev, uint16 block_number)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      block_number - block number
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : Update the record info status to active, this write is valid
 *
 * \endverbatim
 *******************************************************************************************************/
int fee_write_block_active(struct fee_dev *fee_dev, uint16 block_number)
{
    int ret = FEE_FUN_OK;
    struct fee_record_info *record_info = (struct fee_record_info *)(unsigned long int)ROUNDUP((
            unsigned int)block_info_buff, CONFIG_ARCH_CACHE_LINE);
    record_info->record_status = FEE_RECORD_VALID;
    record_info->record_sync = FEE_RECORD_SYNC;

    ret = fee_set_record_status(fee_dev, fee_dev->current_page,
                                fee_dev->record_info_offset - 1U,
                                record_info);

    if (ret) {
        FEE_ERROR("fee_block_write set_record_info FEE_RECORD_VALID status block_number %d failure\n",
              block_number);
        return ret;
    }

    return ret;
}

/** *****************************************************************************************************
 * \brief  Set block to valid state.
 *
 * \verbatim
 * Syntax             : int fee_write_block_valid(struct fee_dev *fee_dev, uint16 block_number,
 *                           boolean *block_valid)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      block_number - block number
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : block_valid - Whether a block update to valid generates Fls operations
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : The block is set to the valid state so that the read operation can be performed
 *
 * \endverbatim
 *******************************************************************************************************/
int fee_write_block_valid(struct fee_dev *fee_dev, uint16 block_number,
                          boolean *block_valid)
{
    int ret = FEE_FUN_OK;
    uint16 block_index = fee_number_to_index(block_number);

    /* Check block index */
    if(FEE_BLOCK_INDEX_DEF == block_index) {
        FEE_ERROR("fee_write_block_valid block_number:%d could not find block index\n",
              block_number);
        return FEE_FUN_FAILED;
    }

    /* If the status is not valid, set it to valid */
    if (!fee_block_valid_check(fee_dev, block_index)) {
        *block_valid = 0;
        ret = fee_block_valid_set(fee_dev, block_index, TRUE);

        /*PRQA S 2992 2*/
        if (ret) {
            FEE_ERROR("fee_block_write set_record_info fee_block_valid status block_number %d failure\n",
                  block_number);
            return ret;
        }
    }

    return ret;
}

/** *****************************************************************************************************
 * \brief  Set block to invalid state.
 *
 * \verbatim
 * Syntax             : int fee_write_block_invalid(struct fee_dev *fee_dev, uint16 block_number,
 *                             boolean *block_invalid)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      block_number - block number
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : block_invalid - Whether a block update to invalid generates Fls operations
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : Set the block to the invalid state and make it unavailable for read and write access
 *
 * \endverbatim
 *******************************************************************************************************/
int fee_write_block_invalid(struct fee_dev *fee_dev, uint16 block_number,
                            boolean *block_invalid)
{
    int ret = FEE_FUN_OK;
    uint16 block_index = fee_number_to_index(block_number);

    /* Check block index */
    if(FEE_BLOCK_INDEX_DEF == block_index) {
        FEE_ERROR("fee_write_block_invalid block_number:%d could not find block index\n",
              block_number);
        return FEE_FUN_FAILED;
    }

    /* If the status is not invalid, set it to invalid */
    if (!fee_block_invalid_check(fee_dev, block_index)) {
        ret = fee_block_invalid_set(fee_dev, block_index, TRUE);

        /*PRQA S 2992 2*/
        if (ret) {
            FEE_ERROR("fee_block_write set_record_info fee_block_invalid status block_number %d failure\n",
                  block_number);
            return ret;
        }

        /* Set the status of the latest record info to FEE_BLOCK_INVALID */
        *block_invalid = TRUE;
        struct fee_record_info *record_info = (struct fee_record_info *)(unsigned long int)ROUNDUP((
                unsigned int)block_info_buff, CONFIG_ARCH_CACHE_LINE);
        record_info->record_status = FEE_BLOCK_INVALID;
        record_info->record_sync = FEE_RECORD_SYNC;

        ret = fee_set_record_status(fee_dev, fee_dev->current_page,
                                    block_status[block_index].block_info_index[fee_dev->current_page],
                                    record_info);

        if (ret) {
            FEE_ERROR("fee_block_write set_record_info FEE_BLOCK_INVALID status block_number %d failure\n",
                  block_number);
            fee_block_invalid_set(fee_dev, block_index, FALSE);
            return ret;
        }

    }

    return ret;
}

/** *****************************************************************************************************
 * \brief  Check whether the block can be read.
 *
 * \verbatim
 * Syntax             : int fee_read_block_check(struct fee_dev *fee_dev, uint16 block_number)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      block_number - block number
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : Check whether the block can be read
 *
 * \endverbatim
 *******************************************************************************************************/
int fee_read_block_check(struct fee_dev *fee_dev, uint16 block_number)
{
    int ret = FEE_FUN_OK;
    uint16 block_index = fee_number_to_index(block_number);

    /* Check block index */
    if(FEE_BLOCK_INDEX_DEF == block_index) {
        FEE_ERROR("fee_read_block_check block_number:%d could not find block index\n",
              block_number);
        return FEE_FUN_FAILED;
    }

    /* Check block invalid */
    if (fee_block_invalid_check(fee_dev, block_index)) {
        FEE_ERROR("fee block invalid block_number:%d\n", block_number);
        return FEE_FUN_FAILED;
    }

    /* Check block valid */
    if (!fee_block_valid_check(fee_dev, block_index)) {
        FEE_ERROR("fee block not valid block_number:%d\n", block_number);
        return FEE_FUN_FAILED;
    }

    return ret;
}

/** *****************************************************************************************************
 * \brief  read block data.
 *
 * \verbatim
 * Syntax             : uint16 fee_read_block_data(struct fee_dev *fee_dev, uint16 block_number,
                           uint16 block_offset, uint8 *data_buffer, uint16 length, boolean *data_sync)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      block_number - block number
 *                      block_offset - block offset
 *                      length - block length
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : data_buffer - read data buff
 *                      data_sync - Whether to perform sync operation
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : Reads the data of the specified block, specifying the length and block offset
 *
 * \endverbatim
 *******************************************************************************************************/
uint16 fee_read_block_data(struct fee_dev *fee_dev, uint16 block_number,
                           uint16 block_offset, uint8 *data_buffer, uint16 length, boolean *data_sync)
{
    uint16 block_index = fee_number_to_index(block_number);
    Fls_LengthType block_data_offset = 0U;

    /* Check block index */
    if(FEE_BLOCK_INDEX_DEF == block_index) {
        FEE_ERROR("fee_read_block_data block_number:%d could not find block index\n",
              block_number);
        return 0;
    }

    /* Calculate the read address information according to the block information */
    block_data_offset = block_status[block_index].block_addr[fee_dev->current_page] + block_offset;
    return (uint16)fee_read_record_data(fee_dev, fee_dev->current_page, block_data_offset,
                                data_buffer, length, data_sync);
}

/** *****************************************************************************************************
 * \brief  read block data sync.
 *
 * \verbatim
 * Syntax             : uint16 fee_read_block_data_sync(struct fee_dev *fee_dev,
 *                                 uint16 block_number,
 *                                 uint16 block_offset, uint8 *data_buffer, uint16 length)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      block_number - block number
 *                      block_offset - block offset
 *                      length - block length
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : data_buffer - read data buff
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : Synchronizing data using buffer reads needs to be synchronized to the read address
 *
 * \endverbatim
 *******************************************************************************************************/
uint16 fee_read_block_data_sync(struct fee_dev *fee_dev,
                                uint16 block_number,
                                uint16 block_offset, uint8 *data_buffer, uint16 length)
{
    uint8 *buff = (uint8 *)(unsigned long int)ROUNDUP((unsigned int)record_data_buff,
                                   CONFIG_ARCH_CACHE_LINE);
    Mcal_MemCpy(data_buffer, buff + (block_offset - ROUNDDOWN(block_offset,
                                (uint32)fee_dev->disk_access_size)), length);
    return length;
}

/** *****************************************************************************************************
 * \brief  swap config.
 *
 * \verbatim
 * Syntax             : int fee_swap_cfg(struct fee_dev *fee_dev, uint16 *fee_active_page,
 *                                       uint16 *fee_erase_page)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : fee_active_page - active page
 *                      fee_erase_page - erase page
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : Configuring swap Status
 *
 * \endverbatim
 *******************************************************************************************************/
int fee_swap_cfg(struct fee_dev *fee_dev, uint16 *fee_active_page,
                 uint16 *fee_erase_page)
{
    int ret = FEE_FUN_OK;
    uint16 swap_page = 0U;

    if ((NULL_PTR == fee_active_page) || (NULL_PTR == fee_erase_page))
        return FEE_FUN_FAILED;

    if (fee_dev->current_page == fee_dev->page_number - 1U)
        swap_page = 0U;
    else
        swap_page = fee_dev->current_page + 1U;

    for (uint16 i = 0; i < FEE_BLOCKS_CFG_NUMBER; i++) {
        fee_block_status_backup(fee_dev, i);
    }

    g_active_page = fee_dev->current_page;
    g_erase_page = swap_page;
    fee_dev->current_page = g_erase_page;
    fee_dev->record_info_offset_swap_backup = fee_dev->record_info_offset;
    fee_dev->record_data_offset_swap_backup = fee_dev->record_data_offset;
    fee_dev->record_info_offset = 0;
    fee_dev->record_data_offset = 0;
    *fee_active_page = g_active_page;
    *fee_erase_page = g_erase_page;
    return ret;
}

/** *****************************************************************************************************
 * \brief  The swap failed, and the status information was restored.
 *
 * \verbatim
 * Syntax             : int fee_swap_recover(struct fee_dev *fee_dev, uint16 fee_active_page)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      fee_active_page - active page
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : FEE_FUN_OK/FEE_FUN_FAILED
 *
 * Description        : The swap failed, and the status information was restored
 *
 * \endverbatim
 *******************************************************************************************************/
int fee_swap_recover(struct fee_dev *fee_dev, uint16 fee_active_page)
{
    int ret = FEE_FUN_OK;
    fee_dev->current_page = g_active_page;
    fee_dev->record_info_offset = fee_dev->record_info_offset_swap_backup;
    fee_dev->record_data_offset = fee_dev->record_data_offset_swap_backup;

    for (uint16 i = 0; i < FEE_BLOCKS_CFG_NUMBER; i++) {
        fee_block_status_recover(fee_dev, i);
    }

    return ret;
}

/** *****************************************************************************************************
 * \brief  swap reads data to the buffer.
 *
 * \verbatim
 * Syntax             : uint16 fee_read_swap_data(struct fee_dev *fee_dev, uint16 block_number,
 *                           uint16 block_offset, uint16 length)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      block_number - block number
 *                      block_offset - block offset
 *                      length - read length
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : Actual read data length
 *
 * Description        : swap reads data to the buffer
 *
 * \endverbatim
 *******************************************************************************************************/
uint16 fee_read_swap_data(struct fee_dev *fee_dev, uint16 block_number,
                          uint16 block_offset, uint16 length)
{
    uint16 block_index = fee_number_to_index(block_number);
    Fls_LengthType block_data_offset = 0U;
    uint8 *buff = NULL_PTR;

    if(FEE_BLOCK_INDEX_DEF == block_index) {
        FEE_ERROR("fee_read_swap_data block_number:%d could not find block index\n",
              block_number);
        return 0;
    }

    block_data_offset = block_status[block_index].block_addr[g_active_page];
    buff = (uint8 *)(unsigned long int)ROUNDUP((unsigned int)record_data_buff,
                                   CONFIG_ARCH_CACHE_LINE);

    Mcal_MemSet(buff, 0xffU, fee_dev->data_buff_size);
    uint16 rlen = (uint16)_MIN(fee_dev->data_buff_size, ROUNDUP(length,
                               (uint32)fee_dev->disk_access_size));

    rlen = (uint16)fee_read_record_data(fee_dev, g_active_page,
                                block_data_offset + block_offset, buff, rlen, NULL_PTR);
    return _MIN(length, rlen);
}

/** *****************************************************************************************************
 * \brief  swap write data to the buffer.
 *
 * \verbatim
 * Syntax             : uint16 fee_write_swap_data(struct fee_dev *fee_dev, uint16 block_number,
 *                           uint16 block_offset, uint16 length)
 *
 * Sync/Async         : Synchronous
 *
 * Reentrancy         : Non reentrant
 *
 * Parameters (in)    : fee_dev - fee device
 *                      block_number - block number
 *                      block_offset - block offset
 *                      length - read length
 *
 * Parameters (inout) : None
 *
 * Parameters (out)   : None
 *
 * Return value       : Actual write data length
 *
 * Description        : swap write data to the buffer
 *
 * \endverbatim
 *******************************************************************************************************/
uint16 fee_write_swap_data(struct fee_dev *fee_dev, uint16 block_number,
                           uint16 block_offset, uint16 length)
{
    uint8 *buff = (uint8 *)(unsigned long int)ROUNDUP((unsigned int)record_data_buff,
                                   CONFIG_ARCH_CACHE_LINE);
    uint16 rlen = (uint16)_MIN(fee_dev->data_buff_size, ROUNDUP(length,
                               (uint32)fee_dev->disk_access_size));
    rlen = (uint16)fee_write_record_data(fee_dev, g_erase_page,
                                 fee_dev->record_data_offset_ops,
                                 buff, rlen);

    if (rlen)
        fee_dev->record_data_offset_ops += ROUNDUP(rlen, (uint32)fee_dev->disk_access_size);

    return _MIN(length, rlen);
}

#define FEE_STOP_SEC_CODE
#include "Fee_MemMap.h"

/* End of file */
